#pragma once
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/wait.h> // 进程等待
#include<pthread.h>
#include<string>
#include<cstring>
#include<functional>

#include"InetAddr.hpp"
#include"Log.hpp"

using namespace log_ns;

enum{
    SOCKET_ERROR = -1,
    BIND_ERROR = -2,
    LISTEN_ERROR
};

const static int gport = 8888;
const static int gsock = -1;
const static int gblcklog = 8;

using command_severice_t = std::function<void(int sockfd, InetAddr addr)>;

class TcpSever
{
public:
    TcpSever(command_severice_t severice, uint16_t port = gport)
        :_port(port)
        ,_listensockfd(gsock)
        ,_isrunning(false)
        ,_severice(severice)
    {}

    void InitSever()
    {
        //1.创建socket
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if(_listensockfd < 0)
        {
            LOG(FATAL, "socket create error \n");
            exit(SOCKET_ERROR);
        }

        LOG(INFO, "socket create sucess, sockfd : %d \n", _listensockfd);

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));

        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY; // 0

        //2.bind socketdf 和 socket addr
        if(::bind(_listensockfd, (const struct sockaddr*)&local, sizeof(local)) < 0)
        {
            LOG(FATAL, "bind error \n");
            exit(BIND_ERROR);
        }

        //3.因为tcp是面向链接的， tcp需要未来不断的能够做到获取链接
        //设置监听状态 服务器可随时被人链接
        if(::listen(_listensockfd, gblcklog) < 0)
        {
            LOG(FATAL, "listen error \n");
            exit(LISTEN_ERROR);
        } 

        LOG(INFO, "listen sucess\n");
    }
    //内部类
    class ThreadData
    {
    public:
        int _sockfd;
        TcpSever* _self;
        InetAddr _addr;
    public:
        ThreadData(int sockfd, TcpSever* self, const InetAddr& addr)
            :_sockfd(sockfd)
            ,_self(self)
            ,_addr(addr)
        {}
    };

    void Loop() 
    {
        //signal(SIGCHLD, SIG_IGN);
        _isrunning = true;

        while(_isrunning)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            //4.获取新连接
            int sockfd = ::accept(_listensockfd, (struct sockaddr*)&client, &len);

            if(sockfd < 0)
            {
                LOG(WARNING, "accept error \n");
                continue;
            }
            InetAddr addr(client);
            LOG(INFO, "get a new link, client info : %s \n", addr.AddrStr().c_str());

            // Version 0 --- 不靠谱版本
            //Service(sockfd, addr);

            // Vision 1 --- 多进程版本
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //child
            //     ::close(_listensockfd); // 写时拷贝

            //     // 底下 父进程阻塞式等待 fork > 0 是子进程id , = 0 是子进程中
            //     //创建孙子进程 直接关闭子进程 父进程就不会等待了 孙子进程就会变成孤儿进程 被系统领养
            //     if(fork() > 0) exit(0);

            //     //子进程退出了 孙子进程继续
            //     Service(sockfd, addr);
            //     exit(0);
            // }
            // //father
            // ::close(sockfd);
            // int n = waitpid(id, nullptr, 0);
            // if(n > 0)
            // {
            //     LOG(INFO, "wait child sucess. \n");
            // }

            //Version 2 --- 多线程版本 不能关闭sockfd 因为线程间共享
            pthread_t tid;
            ThreadData* td = new ThreadData(sockfd, this, addr);
            pthread_create(&tid, nullptr, Execute, td); //新线程进行分离 不设置join

            //Version 3 ----- 线程池版本  //int sockfd, InetAddr addr
            // task_t t = std::bind(&TcpSever::Service, this, sockfd, addr);
            // ThreadPool<task_t>::GetInstance()->Equeue(t);
        }

        _isrunning = false;
    }
    //设为static 去掉this 参数 
    static void* Execute(void *args)
    {
        //分离
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->_self->_severice(td->_sockfd, td->_addr);
        ::close(td->_sockfd);
        delete td;

        return nullptr;
    }

    // void Service(int sockfd, InetAddr addr)
    // {
    //     //长服务 客户端不想停 服务端就不停
    //     while(true)
    //     {
    //         char inbuffer[1024];
    //         ssize_t n = ::read(sockfd, inbuffer, sizeof(inbuffer) - 1);
    //         if(n > 0)
    //         {
    //             inbuffer[n] = 0;
    //             LOG(INFO, "get message from client %s, message : %s\n", addr.AddrStr().c_str(),inbuffer);
    //             std::string echo_string = "[sever echo] #";
    //             echo_string += inbuffer;
    //             ::write(sockfd, echo_string.c_str(), echo_string.size());
    //         }
    //         else if(n == 0) 
    //         {
    //             LOG(INFO, "client %s quit \n", addr.AddrStr().c_str());
    //             break;
    //         }
    //         else
    //         {
    //             break;
    //             LOG(ERROR, "read error \n");
    //         }
    //     }
 
    // }

    ~TcpSever()
    {}


private:
    uint16_t _port;
    int _listensockfd;
    bool _isrunning;

    command_severice_t _severice;
};